package com.nq.service.impl;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.nq.common.SystemVersionEnum;
import com.nq.dao.*;
import com.github.pagehelper.Page;
import com.nq.dao.LogEditTransactionRecordsMapper;
import com.nq.pojo.*;
import com.nq.pojo.vo.UserWithdrawVo;
import com.nq.service.*;
import com.github.pagehelper.PageHelper;

import com.github.pagehelper.PageInfo;

import com.nq.common.ServerResponse;

import com.nq.utils.DateTimeUtil;
import com.nq.utils.DateUtils;
import com.nq.utils.SymmetricCryptoUtil;
import com.nq.utils.email.SendHTMLMail;
import com.nq.utils.smsUtil.AbroadSmsUtil;
import com.nq.utils.stock.WithDrawUtils;

import java.math.BigDecimal;

import java.util.ArrayList;
import java.util.Date;

import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;


@Service("iUserWithdrawService")
public class UserWithdrawServiceImpl implements IUserWithdrawService {

    private static final Logger log = LoggerFactory.getLogger(UserWithdrawServiceImpl.class);


    @Value("${spring.profiles.active}")
    private String active;

    @Autowired
    UserWithdrawMapper userWithdrawMapper;
    @Resource
    private LogEditTransactionRecordsMapper logEditTransactionRecordsMapper;

    @Autowired
    IUserService iUserService;


    @Autowired
    UserMapper userMapper;


    @Autowired
    IAgentUserService iAgentUserService;

    @Autowired
    AgentUserMapper agentUserMapper;

    @Autowired
    IUserPositionService iUserPositionService;

    @Autowired
    IUserBankService iUserBankService;

    @Autowired
    ISiteSettingService iSiteSettingService;

    @Autowired
    ISiteProductService iSiteProductService;

    @Autowired
    IUserUsdtService userUsdtService;

    @Resource
    SendHTMLMail sendHTMLMail;

    @Resource
    private UserCashDetailMapper userCashDetailMapper;

    @Transactional
    public ServerResponse outMoney(Integer type, String amt, String payPwd, HttpServletRequest request) {

        if (StringUtils.isBlank(amt)) {
            return ServerResponse.createByErrorMsg("The cash withdrawal parameter cannot be empty.");
        }

        User user = this.iUserService.getCurrentRefreshUser(request);

        // 校验支付密码
        String userPayPwd = user.getPayPwd();
        if (StringUtils.isBlank(userPayPwd)) {
            return ServerResponse.createByErrorMsg("You have not set a payment password yet. Please set a payment password before making a purchase!");
        }

        // 校验密码是否正确
        if (!SymmetricCryptoUtil.encryptPassword(payPwd).equals(userPayPwd)) {
            boolean isLocked = iUserService.isLocked(User.CASH_PAY_PWD_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("Purchase failed, The password has exceeded 5 times. Please wait for half an hour before making a purchase.");
            }
            return ServerResponse.createByErrorMsg("Purchase failed, The password you entered is incorrect, please re-enter it!");
        }


        if (user.getIsLogin().intValue() == 1) {
            return ServerResponse.createByErrorMsg("User Locked");
        }

        if (StringUtils.isBlank(user.getRealName())) {
            return ServerResponse.createByErrorMsg("No real-name authentication");
        }
        if (StringUtils.isBlank(user.getIdCard())) {
            return ServerResponse.createByErrorMsg("The bank card is not bound");
        }

        // 如果是1，则代表是银行卡
        UserBank userBank = this.iUserBankService.findUserBankByUserId(user.getId());
        if (1 == type) {
            if (userBank == null) {
                return ServerResponse.createByErrorMsg("No bank card added");
            }
        }

        UserUsdt userUsdt = this.userUsdtService.findUserUsdtByUserId(user.getId());
        if (2 == type) {
            if (null == userUsdt) {
                return ServerResponse.createByErrorMsg("No usdt added");
            }
        }

        SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting();
        if ((new BigDecimal(amt)).compareTo(new BigDecimal(siteSetting.getWithMinAmt().intValue())) == -1) {
            return ServerResponse.createByErrorMsg("The amount of withdrawal shall not be less than $" + siteSetting.getWithMinAmt());
        }


        int with_time_begin = siteSetting.getWithTimeBegin().intValue();
        int with_time_end = siteSetting.getWithTimeEnd().intValue();

        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        if(siteProduct.getHolidayDisplay()){
            return ServerResponse.createByErrorMsg("You can't make withdrawals on weekends or holidays.！");
        }

        if (!WithDrawUtils.checkIsWithTime(with_time_begin, with_time_end)) {
            return ServerResponse.createByErrorMsg("The withdrawal failed, and the withdrawal time was from " + with_time_begin + "to " + with_time_end);
        }

        // 可用现金
        BigDecimal enable_amt = user.getEnableAmt();
        int compareAmt = enable_amt.compareTo(new BigDecimal(amt));
        if (compareAmt == -1) {
            return ServerResponse.createByErrorMsg("The withdrawal failed, and the user's available funds were insufficient.");
        }


        BigDecimal user_all_amt = user.getUserAmt();
        BigDecimal reckon_all_amt = user_all_amt.subtract(new BigDecimal(amt));
        BigDecimal reckon_enable_amt = enable_amt.subtract(new BigDecimal(amt));
        // 总金额
//        user.setUserAmt(reckon_all_amt);
        // 可用现金
        user.setEnableAmt(reckon_enable_amt);

        log.info("用户提现{}，金额 = {},总资金 = {},可用资金 = {}", new Object[]{user.getId(), amt, user_all_amt, enable_amt});
        log.info("提现后，总金额={},可用资金={}", reckon_all_amt, reckon_enable_amt);

        int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user);
        if (updateUserCount > 0) {
            log.info("修改用户资金成功");
        } else {
            log.error("修改用户资金失败");
            throw new IllegalArgumentException("User withdrawal, failure to modify user funds");
        }


        UserWithdraw userWithdraw = new UserWithdraw();
        userWithdraw.setUserId(user.getId());
        userWithdraw.setNickName(user.getRealName());
        userWithdraw.setAgentId(user.getAgentId());
        userWithdraw.setWithAmt(new BigDecimal(amt));
        userWithdraw.setApplyTime(new Date());
        userWithdraw.setWithName(user.getRealName());
        userWithdraw.setType(type);
        if (UserWithdraw.BANK_TYPE.equals(type)) {
            userWithdraw.setBankNo(userBank.getBankNo());
            userWithdraw.setBankName(userBank.getBankName());
            userWithdraw.setBankAddress(userBank.getIfscNo());
        } else if (UserWithdraw.USDT_TYPE.equals(type)) {
            userWithdraw.setNetType(userUsdt.getNetType());
            userWithdraw.setUsdtAddr(userUsdt.getUsdtAddr());
        }

        userWithdraw.setWithStatus(Integer.valueOf(0));
        // 手续费
        BigDecimal withfee = siteSetting.getWithFeePercent().multiply(new BigDecimal(amt)).add(new BigDecimal(siteSetting.getWithFeeSingle().intValue()));
        userWithdraw.setWithFee(withfee);
        this.userWithdrawMapper.insert(userWithdraw);

        User currentUser = userMapper.selectById(user.getId());
        // 记录充值流水
        UserCashDetail ucd = new UserCashDetail();
        ucd.setAgentId(user.getAgentId());
        ucd.setAgentName(user.getAgentName());
        ucd.setUserId(user.getId());
        ucd.setUserName(user.getRealName());
        ucd.setDeType("User Cash");
        ucd.setDeAmt(new BigDecimal(amt).negate());
        ucd.setDeSummary("The user cash successfully, and the total amount after the cash:" + currentUser.getEnableAmt() + ", Cash withdrawal amount: " + amt + ", Service charge: " + withfee);
        ucd.setAddTime(new Date());
        ucd.setIsRead(Integer.valueOf(0));
        int insertCount = this.userCashDetailMapper.insert(ucd);

        if (insertCount > 0) {
            return ServerResponse.createBySuccessMsg("Successful withdrawal");
        }

        log.error("保存提现记录失败");

        throw new IllegalArgumentException("User withdrawal, failed to save the withdrawal record");
    }


    public ServerResponse<PageInfo> findUserWithList(Integer withStatus, HttpServletRequest request, int pageNum, int pageSize) {

        PageHelper.startPage(pageNum, pageSize);


        User user = this.iUserService.getCurrentRefreshUser(request);


        List<UserWithdraw> userWithdraws = this.userWithdrawMapper.findUserWithList(user.getId(), withStatus);


        PageInfo pageInfo = new PageInfo(userWithdraws);


        return ServerResponse.createBySuccess(pageInfo);

    }


    public ServerResponse userCancel(Integer withId) {

        if (withId == null) {

            return ServerResponse.createByErrorMsg("Id cannot be empty");

        }


        UserWithdraw userWithdraw = this.userWithdrawMapper.selectByPrimaryKey(withId);

        if (userWithdraw == null) {

            return ServerResponse.createByErrorMsg("Order does not exist");

        }


        if (0 != userWithdraw.getWithStatus().intValue()) {

            return ServerResponse.createByErrorMsg("The current order cannot be cancelled.");

        }


        userWithdraw.setWithStatus(Integer.valueOf(3));

        userWithdraw.setWithMsg("用户取消出金");

        int updateCount = this.userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);

        if (updateCount > 0) {

            log.info("修改用户提现订单 {} 状态成功", withId);


            User user = this.userMapper.selectByPrimaryKey(userWithdraw.getUserId());

//            user.setUserAmt(user.getUserAmt().add(userWithdraw.getWithAmt()));

            user.setEnableAmt(user.getEnableAmt().add(userWithdraw.getWithAmt()));

            int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user);

            if (updateUserCount > 0) {

                log.info("反还用户资金，总 {} 可用 {}", user.getUserAmt(), user.getEnableAmt());

                return ServerResponse.createBySuccessMsg("Cancelled successfully");

            }

            return ServerResponse.createByErrorMsg("Failure to cancel");

        }


        log.info("修改用户提现订单 {} 状态失败", withId);

        return ServerResponse.createByErrorMsg("Failure to cancel");

    }


    public ServerResponse listByAgent(Integer type, String realName, Integer withStatus, HttpServletRequest request, int pageNum, int pageSize) {
        AgentUser currentAgent = this.iAgentUserService.getCurrentAgent(request);
        if (currentAgent == null) {
            return ServerResponse.createByErrorMsg("请先登录后查看！");
        }

        Integer searchId = currentAgent.getId();
        PageHelper.startPage(pageNum, pageSize);
        List<UserWithdraw> userWithdraws = this.userWithdrawMapper.listByAgent(searchId, realName, withStatus, type);
        PageInfo pageInfo = new PageInfo(userWithdraws);
        return ServerResponse.createBySuccess(pageInfo);

    }

    public ServerResponse<PageInfo> listByAdmin(String accountType, String withStatus, String type, Integer agentId, Integer userId, String realName, String userPhone,
                                                Integer state, String beginTime, String endTime, HttpServletRequest request, int pageNum, int pageSize) {

        Page<Object> page = PageHelper.startPage(pageNum, pageSize);
        List<UserWithdrawVo> userWithdraws = this.userWithdrawMapper.listByAdmin(accountType, agentId, userId, realName, state, beginTime, endTime,withStatus,type, userPhone);
        PageInfo pageInfo = new PageInfo(page);
        pageInfo.setList(userWithdraws);
        return ServerResponse.createBySuccess(pageInfo);

    }

    @Transactional
    public ServerResponse updateState(Integer withId, Integer state, String authMsg) throws Exception {

        UserWithdraw userWithdraw = this.userWithdrawMapper.selectByPrimaryKey(withId);
        if (userWithdraw == null) {
            return ServerResponse.createByErrorMsg("Order does not exist");
        }


        if (userWithdraw.getWithStatus().intValue() != 0) {
            return ServerResponse.createByErrorMsg("The withdrawal order has been processed. Don't repeat the operation.");
        }


        if (state.intValue() == 2 && StringUtils.isBlank(authMsg)) {
            return ServerResponse.createByErrorMsg("Failure information is required");
        }

        User user = this.userMapper.selectByPrimaryKey(userWithdraw.getUserId());
        if (user == null) {
            return ServerResponse.createByErrorMsg("User does not exist");
        }

        if (state.intValue() == 2) {
            BigDecimal user_amt = user.getUserAmt().add(userWithdraw.getWithAmt());
            log.info("管理员确认提现订单失败，返还用户 {} 总资金，原金额 = {} , 返还后 = {}", new Object[]{user.getId(), user.getUserAmt(), user_amt});
            BigDecimal user_enable_amt = user.getEnableAmt().add(userWithdraw.getWithAmt());
            log.info("管理员确认提现订单失败，返还用户 {} 可用资金，原金额 = {} , 返还后 = {}", new Object[]{user.getId(), user.getEnableAmt(), user_enable_amt});
            user.setEnableAmt(user_enable_amt);


            int updateCount = this.userMapper.updateByPrimaryKeySelective(user);
            if (updateCount > 0) {
                log.info("提现失败，返还用户资金成功！");
            } else {
                log.error("返还用户资金出错，抛出异常");
                throw new Exception("There was an error in modifying the user's funds and throwing an exception.");
            }
        }

        userWithdraw.setWithStatus(Integer.valueOf((state.intValue() == 1) ? 1 : 2));
        userWithdraw.setWithMsg(authMsg);
        userWithdraw.setTransTime(new Date());
        int updateCount = this.userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
        if (updateCount > 0) {
            log.info("修改订单状态成功");
        } else {
            throw new Exception("Failed to modify order status!");
        }

        String deType = state.intValue() == 1 ? "Withdrawal Successful" : "Withdrawal Failure";
        String deSummary = state.intValue() == 1 ?
                "The user withdrawal successfully, and Cash withdrawal amount："+ userWithdraw.getWithAmt() +", Users Funds currently available： " + user.getEnableAmt() :
                "The user withdrawal  Failure, Return user funds：" + userWithdraw.getWithAmt() + ", Users Funds currently available： " + user.getEnableAmt();

        int insertCount = 0;
        // 用户提现流水 这里在用户提现的时候已经加上流水了  所以审核的时候只有审核失败需要退款的时候再加流水
        if (state.intValue() == 2) {
            UserCashDetail ucd = new UserCashDetail();
            ucd.setAgentId(user.getAgentId());
            ucd.setAgentName(user.getAgentName());
            ucd.setUserId(user.getId());
            ucd.setUserName(user.getRealName());
            ucd.setDeType(deType);
            ucd.setDeAmt(userWithdraw.getWithAmt());
            ucd.setDeSummary(deSummary);
            ucd.setAddTime(new Date());
            ucd.setIsRead(Integer.valueOf(0));
            insertCount = this.userCashDetailMapper.insert(ucd);
        }

        // 发送邮箱
        if(SystemVersionEnum.global.name().equals(active)) {
            sendHTMLMail.sendWithdrawEmail(user, userWithdraw);
        }
        return ServerResponse.createBySuccessMsg("Successfully recharged！");
    }


    public int deleteByUserId(Integer userId) {
        return this.userWithdrawMapper.deleteByUserId(userId);
    }


    public BigDecimal CountSpWithSumAmtByState(Integer withState) {
        return this.userWithdrawMapper.CountSpWithSumAmtByState(withState);
    }

    public BigDecimal CountSpWithSumAmTodaytByState(Integer withState) {
        return this.userWithdrawMapper.CountSpWithSumAmTodaytByState(withState);
    }

    public ServerResponse deleteWithdraw(Integer withdrawId) {
        if (withdrawId == null) {
            return ServerResponse.createByErrorMsg("Id cannot be empty");
        }
        int updateCount = this.userWithdrawMapper.deleteByPrimaryKey(withdrawId);
        if (updateCount > 0) {
            return ServerResponse.createBySuccessMsg("Deleted successfully");
        }
        return ServerResponse.createByErrorMsg("Failed to delete");
    }
    //导出用户提现
    @Override
    public List<UserWithdrawVo> exportByAdmin(String accountType, String withStatus, String type, Integer agentId, Integer userId, String realName, String userPhone, Integer state, String beginTime, String endTime, HttpServletRequest request) {
        return this.userWithdrawMapper.listByAdmin(accountType, agentId, userId, realName, state, beginTime, endTime,withStatus,type,userPhone);
    }

    @Override
    @Transactional
    public ServerResponse updateWithdraw(Integer id, BigDecimal withAmt, BigDecimal withFee, String applyTime, String transTime) {
        UserWithdraw userWithdraw = this.userWithdrawMapper.selectByPrimaryKey(id);
        if (userWithdraw == null) {
            return ServerResponse.createByErrorMsg("Order does not exist");
        }

        // 设置时区
        Date dateTime = DateTimeUtil.strToDate(applyTime);
        Date dateTime1 = DateTimeUtil.strToDate(transTime);
        UserWithdraw updateWith = new UserWithdraw();
        updateWith.setId(id);
        updateWith.setApplyTime(dateTime);
        updateWith.setTransTime(dateTime1);


        updateWith.setWithAmt(withAmt);
        updateWith.setWithFee(withFee);
        int updateCount = this.userWithdrawMapper.updateById(updateWith);

        // 新增修改的记录
        StringBuilder record = new StringBuilder();
        record.append("提现交易->订单ID：" + userWithdraw.getId() + "; ");
        record.append("修改时间：" + DateUtils.now() + ";");
        record.append("提现金额由" + updateWith.getWithAmt() + "修改为" + withAmt + ";");
        record.append("提现手续费由" + updateWith.getWithFee() + "修改为" + withFee + ";");
        record.append("订单申请时间由" + updateWith.getApplyTime() + "修改为" + applyTime + ";");
        record.append("订单出金时间由" + updateWith.getTransTime() + "修改为" + transTime + ";");

        // 修改记录
        LogEditTransactionRecords transactionRecords = new LogEditTransactionRecords();
        transactionRecords.setRecord(record.toString());
        transactionRecords.setOrderNo(userWithdraw.getId().toString());
        transactionRecords.setCreateTime(new Date());
        logEditTransactionRecordsMapper.insert(transactionRecords);

        if (updateCount > 0) {

            return ServerResponse.createBySuccessMsg("Successful operation！");

        }

        return ServerResponse.createByErrorMsg("Operation failed！");
    }

}

